package com.yale.cxfsoapwc.controller;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.xml.namespace.QName;

/**
 * @author yale
 * @date 2017/8/16
 * @version 2.0
 */
@RequestMapping(value = "soapClient")
@Controller
public class UserController {

    /**
     * SIB和SEI的@WebService注解中的targetNamespace要相同，
     * SIB的@WebService的targetNamespace对应为SEI的targetNamespace。
     *
     * CXF 动态代理模式，不用生成本地WS代理类，
     * 通过反射调用 WS 的对应的方法，传入相应的参数
     * 访问cxf-soap-ws项目下的webservice;
     * 测试jaxws-rt发布WebService web方式。
     * 此测试实例，用于测试SEI和SIB的targetNamespace指定的webService接口：
     * http://localhost:1003/soap/user?wsdl；
     * @return
     */
    @GetMapping(value = "same", produces = "text/plain;charset=utf-8")
    public String sopaSame(){
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient("http://localhost:1003/soap/user?wsdl");
        Object[] objects = null;
        try{
            objects = client.invoke("getUser", 10002L);
        }catch(Exception e){
            e.printStackTrace();
        }

        //输出调用结果
        System.out.println(objects[0].getClass());
        System.out.println(objects[0].toString());
        return "success";
    }

    /**
     * 第二种方式动态客户端直接通过QName调用WebService对应的操作，
     * 这种方式针对SIB和SEI的targetNamespace不相同，同时不再同一个包：
     * 动态客户端：
     *
     * CXF 动态代理模式，不用生成本地WS代理类，
     * 通过反射调用 WS 的对应的方法，传入相应的参数
     * 访问cxf-soap-wws项目下的webservice;
     * 测试jaxws-rt发布WebService web方式。
     * 此测试实例，用于测试SEI和SIB的targetNamespace未指定的webService接口：
     * http://localhost:8080/cxf_server_web/jws_services?wsdl
     */
    private static final String JWS_RT_WSDL_URI ="http://localhost:1003/soap/diff?wsdl";
    @GetMapping(value = "dynamic")
    public void cxfDynamicClientOnJwsRtWebWithQname(){
        System.out.println("======CXF-WS Dynamic Client start！======");
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client =  dcf.createClient(JWS_RT_WSDL_URI);
        HTTPConduit conduit = (HTTPConduit)client.getConduit();
        HTTPClientPolicy policy = new HTTPClientPolicy();
        policy.setConnectionTimeout(10000);
        policy.setAllowChunking(false);
        policy.setReceiveTimeout(10000);
        conduit.setClient(policy);
        //获取操作对应的Qname
        QName operateQName = getOperateQName(client,"getUser");
        //如果Qname已知，可以通过如下方式，直接创建QName
//		operateQName = new QName("http://service.jws/","login");
        Object[] invokeResult = null;
        try {
            invokeResult = client.invoke(operateQName, 10002L);
        } catch (Exception e){
            e.printStackTrace();
        }

        System.out.println("=======sumResult:" + invokeResult[0]);
    }

    /**
     * 针对SEI和SIB不在统一个包内的情况，先查找操作对应的Qname，
     * client通过Qname调用对应操作
     * @param client
     * @param operation
     * @return
     */
    private static QName getOperateQName(Client client, String operation){
        Endpoint endpoint = client.getEndpoint();
        QName opName = new QName(endpoint.getService().getName().getNamespaceURI(), operation);
        BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();
        if (bindingInfo.getOperation(opName) == null) {
            for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
                if (operation.equals(operationInfo.getName().getLocalPart())) {
                    opName = operationInfo.getName();
                    break;
                }
            }
        }
//        log.info("Operation:"+operation+",namespaceURI:" + opName.getNamespaceURI());
        System.out.println("Operation:"+operation+",namespaceURI:" + opName.getNamespaceURI());
        return opName;
    }

}
